/* Soubor je ulozen v kodovani UTF-8.
 * Kontrola kódování: Příliš žluťoučký kůň úpěl ďábelské ódy.
 */
package cz.pecinovsky.english.pojj.gui_obr;

import java.awt.BorderLayout;
import java.awt.Point;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;

import java.util.Date;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;



/*******************************************************************************
 * Instance třídy {@code GUI_OBR_1} přestavují grafické aplikace
 * pro testování práce s grafikou, obrázky a posluchači událostí.
 * <p>
 * Tato verze stále ukazuje pouze tři předem zadané obrázky, ale má již
 * jednoduchou nabídku umožňující zadat průběžné zaznamenávání akcí do žurnálu.
 * Žurnál si ale není schopen zapamatovat akce za všech okolností.
 *
 * @author    Rudolf PECINOVSKÝ
 * @version   0.00.000,  0.0.2006
 */
public class GUI_OBR_1
{
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

    /** Souřadnice, na které se aplikační okno přesune po spuštění GUI.
     *  To má smysl především při zobrazování na sekundárním monitoru. */
    private static final Point POINT_0 = new Point(0, 0);       //(-600, 0);



//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================

    /** Složka, ve které se nacházejí soubory s obrázky. V této verzi
     *  je sice konstantní, ale v dalších ji umožníme nastavovat.  */
    private static String názevSložkyZdrojů;



//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================

    static {
        try {
            názevSložkyZdrojů =
                new File(GUI_OBR_4.class.getResource("OBR").toURI()).
                         getCanonicalPath() + "\\";
        }catch(Exception ex) {
            throw new RuntimeException(
                    "Nepodařilo se připravit složky se zdroji",ex);
        }
    }



//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================

    /** Aplikační okno. */
    private final JFrame frmOkno =
            new JFrame("Práce se soubory a obrázky - verze 1");



//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================

    //Následující atributy jsou sice také konstantní,
    //ale budu-li je daklarovat jako proměnné,
    //nebudu je muset všechny inicializovat v konstruktoru

    private JLabel    lblObrázek;   //Návěští zobrazující vykreslovaný obrázek

    private Icon      icoChyba;     //Obrázek chyby
    private Icon      icoVlastnost; //Obrázek vlastnosti
    private Icon      icoNevím;     //Obrázek otazníku

    private JButton   btnChyba;     //Tlačítko pro obrázek chyby
    private JButton   btnVlastnost; //Tlačítko pro obrázek vlastnosti
    private JButton   btnNevím;     //Tlačítko pro obrázek otazníku
    private JButton   btnNic;       //Tlačítko zavřená panelu obrázků

    private JMenuBar  mnbNabídka;

    private JMenu             mnuSoubor;
    private JMenuItem         mniOtevři;
    private JCheckBoxMenuItem mniŽurnál;

    private JMenu     mnuNápověda;
    private JMenuItem mniOAplikaci;

    private File    file;
    private Writer  výstup;
    private boolean záznam = false;



//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================
//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * Vytvoří instanci aplikace přičemž konstrukce zesložitěla, takže
     * konstruktor pověřuje jednotlivými úkoly samostatné soukromé metody.
     */
    public GUI_OBR_1()
    {
        //Následující posunutí má smysl pouze tehdy,
        //cheme-li aplikační okno zobrazit na sekundárním monitoru
        frmOkno.setLocation(POINT_0);

        frmOkno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        připravNabídku();           //Připraví hlavní nabídku
        připraPanely();             //Připrav jednotlivé panely

        //Aktivace aplikačního okna
        frmOkno.pack();             //Optimalizuje velikost vytvořeného okna
        frmOkno.setVisible(true);   //a zviditelní je
    }



//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================
//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================
//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================

    /***************************************************************************
     * Připraví v aplikačním okně hlavní nabídku
     */
    private void připravNabídku()
    {
        mnbNabídka = new JMenuBar();    //Vytvoření prázdné nabídkové lišty
        připravNabídkuSoubor();         //Přidání požadovaných nabídek
        připravNabídkuNápověda();
        frmOkno.setJMenuBar(mnbNabídka);
    }


    /***************************************************************************
     * Připraví nabídku Nápověda.
     */
    private void připravNabídkuNápověda()
    {
        mnuNápověda = new JMenu("Nápověda");
        mnuNápověda.setMnemonic('N');
        mniOAplikaci = mnuNápověda.add("Nic ti nepovim");

        mnbNabídka.add(mnuNápověda);
    }


    /***************************************************************************
     * Připraví nabídku Soubor.
     */
    private void připravNabídkuSoubor()
    {
        //Připravíme položku (nabídku) v hlavní nabídce
        mnuSoubor = new JMenu("Soubor");     //Text položky nabídky
        mnuSoubor.setMnemonic('S');          //Klávesová zkratka
        mnbNabídka.add(mnuSoubor);

        //Pokračujeme položkami v právě přidané nabídce

        //Otevření souboru, do nějž budeme ukládat mniŽurnál
        mniOtevři = mnuSoubor.add("Otevři");
        mniOtevři.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                zadejSoubor();
            }
        });

        //Přepínač ovlivňující, zda se bude zaznamenávat
        mniŽurnál = new JCheckBoxMenuItem("Žurnál");
        mniŽurnál.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent ie) {
                //Pokračování podle stavu zaškrtnutí
                if(mniŽurnál.getState()) {  //Budeme zaznamenávat
                    //Není-li přpraven žádný mnuSoubor, připrav jej
                    if(file == null) {
                        zadejSoubor();
                        if(file == null) {
                            //Soubor se nepodařilo připravit =>
                            // => zaznamenávat se nebude
                            mniŽurnál.setState(false);
                        }
                        else { //Soubor preo žurnál je připraven
                            try {
                                //Připrav přísušný výstupní proud
                                výstup = new OutputStreamWriter(
                                             new FileOutputStream(file));
                            } catch(FileNotFoundException exc) {
                                throw new RuntimeException(
                                    "\nNepodařilo se otevřít soubor", exc);
                            }
                        }
                    }
                }
                else {  //Nebudeme zaznamenávat = konec záznamu
                    if(výstup != null) {
                        try {
                            výstup.close(); //Musíme zavřít výstup
                        } catch(IOException exc) {
                            throw new RuntimeException(
                                "\nSoubor se nepodařilo zavřít", exc);
                        }
                    }
                }
            }
        });
        mnuSoubor.add(mniŽurnál);
    }


    /***************************************************************************
     * Připraví jednotlivé panely aplikačního okna
     */
    private void připraPanely()
    {
        //Výzva u horního okraje
        frmOkno.add(new JLabel("Který obrázek chceš vidět?"),
                    BorderLayout.NORTH);

        //Obrázky, které se budou zobrazovat ve středu
        icoChyba     = new ImageIcon(názevSložkyZdrojů + "Chyba.png");
        icoVlastnost = new ImageIcon(názevSložkyZdrojů + "Vlastnost.png");
        icoNevím     = new ImageIcon(názevSložkyZdrojů + "Nevím.png");

        lblObrázek   = new JLabel();
        frmOkno.add(lblObrázek, BorderLayout.CENTER);

        //Tlačítka umisťovaná u spodního okjraje
        btnChyba     = new JButton("Chyba");
        btnVlastnost = new JButton("Vlastnost");
        btnNevím     = new JButton("Nevím");
        btnNic       = new JButton("Nic");

        //Border layout dovoluje umístit do každé zóny jedinou komponentu
        //Tlačítek je více => potřebujeme je umístit do panelu
        JPanel panel = new JPanel();
        panel.add(btnChyba);
        panel.add(btnVlastnost);
        panel.add(btnNevím);
        panel.add(btnNic);
        frmOkno.add(panel, BorderLayout.SOUTH);

        //Všechna talčítka mají společného posluchače
        ActionListener posluchač = new PosluchačTlačítka();
        btnChyba     .addActionListener(posluchač);
        btnVlastnost .addActionListener(posluchač);
        btnNevím     .addActionListener(posluchač);
        btnNic       .addActionListener(posluchač);
    }


    /***************************************************************************
     * Požádá uživatele o zadání souboru pro žurnál.
     */
    private void zadejSoubor()
    {
        final JFileChooser fc = new JFileChooser();
        //Vynuluje file pro případ, že by uživatel nic nezadal
        file = null;
        int ret = fc.showOpenDialog(frmOkno);
        if (ret == JFileChooser.APPROVE_OPTION) {
            //Pokud uživatel něco zadal, uloží informaci do proměnné file
            file = fc.getSelectedFile();
        }
    }



//== INTERNÍ DATOVÉ TYPY =======================================================

    /***************************************************************************
     * Instance třídy PosluchačTlačítka představuje společného posluchače
     * všech tlačítek.
     * Je definována jako vnitřní, abychom mohli používat atributy instance.
     */
    private class PosluchačTlačítka implements ActionListener
    {
        /***********************************************************************
         * {@inheritDoc}
         * @param e Očekávaná událost
         */
        @Override
        public void actionPerformed(ActionEvent e) {
            //Zjistím název toho, kdo mne volal
            String zdroj = e.getActionCommand();

            //A porovnám jej s texty na tlačítcích
            if(zdroj.equals(btnChyba.getText())) {
                lblObrázek.setIcon(icoChyba);
            }
            else if(zdroj.equals(btnVlastnost.getText())) {
                lblObrázek.setIcon(icoVlastnost);
            }
            else if(zdroj.equals(btnNevím.getText())) {
                lblObrázek.setIcon(icoNevím);
            }
            else if(zdroj.equals(btnNic.getText())) {
                lblObrázek.setIcon(new ImageIcon());
            }
            else {
                throw new RuntimeException("Neznámá událost");
            }
            //Obrázek mohl změnit velikost okna => musím ji aktualizovat
            frmOkno.pack();

            //Je-li zapnut záznam do žurnálu, zanes informací o provedené akci
            if(mniŽurnál.getState()) {
                try {
                    výstup.write("" + (new Date()) + " - " + zdroj + "\n");
                    výstup.flush();
                } catch(IOException exc) {
                    throw new RuntimeException(
                        "\nChyba při výstupu do souboru", exc);
                }
            }
        }
    }



//== TESTY A METODA MAIN =======================================================

    /***************************************************************************
     * Testovací metoda.
     */
     public static void test() {
         new GUI_OBR_1();
     }


    /***************************************************************************
     * @param args Parametry příkazového řádku - nepoužívají se */
     public static void main(String[] args)  {  test();  }
}
